//////////////
// water.fx //
//////////////


/////////////
// GLOBALS //
/////////////
matrix World;
matrix View;
matrix Projection;
matrix Reflection;
Texture2D waterTexture;
Texture2D reflectionTexture;
Texture2D refractionTexture;
Texture2D normalTexture;
Texture2D dudvTexture;
float waterTranslation;
float reflectScale;
float refractScale;

bool useDUDVMap = true;


///////////////////
// SAMPLE STATES //
///////////////////
SamplerState SampleType
{
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = Wrap;
    AddressV = Wrap;
};


//////////////
// TYPEDEFS //
//////////////
struct VS_INPUT
{
    float4 position : POSITION;
    float2 texNormal : TEXCOORD0;
};

struct VS_OUTPUT
{
    float4 position : SV_POSITION;
    float2 texNormal : TEXCOORD0;
	float4 reflectionPosition : TEXCOORD1;
    float4 refractionPosition : TEXCOORD2;
};


////////////////////////////////////////////////////////////////////////////////
// Vertex Shader
////////////////////////////////////////////////////////////////////////////////
VS_OUTPUT VS(VS_INPUT input)
{
    VS_OUTPUT output = (VS_OUTPUT)0;
    matrix reflectProjectWorld;
	matrix viewProjectWorld;

	//Calculate vertex position
    output.position = mul(input.position, World);
    output.position = mul(output.position, View);
    output.position = mul(output.position, Projection);

    output.texNormal = input.texNormal;

	//Projective texture: calculate the vertex position for reflection
	output.reflectionPosition = mul(input.position, World);
	output.reflectionPosition = mul(output.reflectionPosition, Reflection);
	output.reflectionPosition = mul(output.reflectionPosition, Projection);

	//Projective texture: calculate the vertex position for refraction
	output.refractionPosition = mul(input.position, World);
	output.refractionPosition = mul(output.refractionPosition, View);
	output.refractionPosition = mul(output.refractionPosition, Projection);

	return output;
}

////////////////////////////////////////////////////////////////////////////////
// Pixel Shader
////////////////////////////////////////////////////////////////////////////////
float4 PS(VS_OUTPUT input) : SV_Target
{
	float2 reflectTexCoord;
	float2 refractTexCoord;
	float4 normalMap;
	float4 dudvMap;
	float4 waterColor;
	float3 normal;
	float3 dudvNormal;
	float4 reflectionColor;
	float4 refractionColor;
	float4 color;

	//Sample the water texture color
	waterColor = waterTexture.Sample(SampleType, input.texNormal);

	//Simulate waves: change the y coordinates from the normal map
	input.texNormal.y += waterTranslation;
	
	// reflectTexCoord.x and .y are in range [-1, 1]. In order to be texture coordinates, adjust them to range [0, 1] and
	// calculate the projected reflection texture coordinates.
    reflectTexCoord.x = input.reflectionPosition.x / input.reflectionPosition.w / 2.0f + 0.5f;
    reflectTexCoord.y = -input.reflectionPosition.y / input.reflectionPosition.w / 2.0f + 0.5f;
	
	// refractTexCoord.x and .y are in range [-1, 1]. In order to be texture coordinates, adjust them to range [0, 1] and
	// calculate the projected reflection texture coordinates.
    refractTexCoord.x = input.refractionPosition.x / input.refractionPosition.w / 2.0f + 0.5f;
    refractTexCoord.y = -input.refractionPosition.y / input.refractionPosition.w / 2.0f + 0.5f;
	
	// Sample the normal from the normalmap texture.
	normalMap = normalTexture.Sample(SampleType, input.texNormal);
	// Expand the range of the normal from [0,1] to [-1,+1].
	normal = (normalMap.xyz * 2.0f) - 1.0f;

	dudvMap = dudvTexture.Sample(SampleType, input.texNormal);
	// Expand the range of the normal from [0,1] to [-1,+1].
	dudvNormal = (dudvMap.xyz * 2.0f) - 1.0f;

	// Re-position the texture coordinate sampling position by the normal map value to simulate the rippling wave effect.
	reflectTexCoord = reflectTexCoord + (normal.xy * reflectScale);
	refractTexCoord = refractTexCoord + (normal.xy * reflectScale);

	if(useDUDVMap)
		refractTexCoord = refractTexCoord + (dudvNormal.xy * refractScale);


	// Sample the texture pixels from the textures using the updated texture coordinates.
    reflectionColor = reflectionTexture.Sample(SampleType, reflectTexCoord);
    refractionColor = refractionTexture.Sample(SampleType, refractTexCoord);

	// Combine the reflection and refraction results for the final color.
	color = lerp(reflectionColor, refractionColor, 0.8f);
	color = lerp(color, waterColor, 0.3f);

	return color;
}


////////////////////////////////////////////////////////////////////////////////
// Technique
////////////////////////////////////////////////////////////////////////////////
technique10 WaterTechnique
{
    pass pass0
    {
        SetVertexShader(CompileShader(vs_4_0, VS()));
        SetPixelShader(CompileShader(ps_4_0, PS()));
        SetGeometryShader(NULL);
    }
}